Unit V: ASP.NET Core Web API

Hands-On Interactive Session & Free Compiler Guide

💡 How to use this Hands-On Guide:
1. Read the concept.
2. Click Copy Code on the code blocks.
3. Go to the free online compiler .NET Fiddle or Replit.
4. Paste the code and hit Run to see the output live!

1. Designing RESTful Web API

Concept: A RESTful API uses standard HTTP verbs (GET, POST, PUT, DELETE) to perform operations on resources (like Products, Users). It is stateless and returns JSON.

ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;

namespace MyWebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private static List<Product> _products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Price = 1200 },
            new Product { Id = 2, Name = "Mouse", Price = 25 }
        };

        // GET: api/products (Read All)
        [HttpGet]
        public ActionResult<IEnumerable<Product>> GetProducts()
        {
            return Ok(_products);
        }

        // GET: api/products/1 (Read One)
        [HttpGet("{id}")]
        public ActionResult<Product> GetProduct(int id)
        {
            var product = _products.FirstOrDefault(p => p.Id == id);
            if (product == null) return NotFound(); // 404
            return Ok(product); // 200
        }

        // POST: api/products (Create)
        [HttpPost]
        public ActionResult<Product> CreateProduct([FromBody] Product product)
        {
            product.Id = _products.Max(p => p.Id) + 1;
            _products.Add(product);
            return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product); // 201
        }

        // DELETE: api/products/1 (Delete)
        [HttpDelete("{id}")]
        public IActionResult DeleteProduct(int id)
        {
            var product = _products.FirstOrDefault(p => p.Id == id);
            if (product == null) return NotFound();
            _products.Remove(product);
            return NoContent(); // 204
        }
    }

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

2. Hands-On: Simulating a Web API in Console

Since online fiddles are primarily for console apps, let's write a C# program that mimics a REST API routing system. This helps you understand the logic behind HTTP verbs and status codes before deploying to a real server.

Try this in .NET Fiddle (Free)

Copy the code below, paste it into dotnetfiddle.net, and hit Run. This simulates a client calling your API.

Program.cs (Console Simulation)
using System;
using System.Collections.Generic;
using System.Linq;

// 1. Define the Model
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

// 2. Simulate a Web API Controller
public class ProductsApiController
{
    private static List<Product> _db = new List<Product>
    {
        new Product { Id = 1, Name = "Laptop", Price = 1200 },
        new Product { Id = 2, Name = "Mouse", Price = 25 }
    };

    // GET /api/products
    public void GetAll() 
    {
        Console.WriteLine("HTTP 200 OK:");
        foreach(var p in _db) Console.WriteLine($"  - {p.Id}: {p.Name} (${p.Price})");
    }

    // POST /api/products
    public void Create(string name, decimal price)
    {
        var newProduct = new Product { Id = _db.Max(p => p.Id) + 1, Name = name, Price = price };
        _db.Add(newProduct);
        Console.WriteLine($"HTTP 201 Created: Added {newProduct.Name} with ID {newProduct.Id}");
    }

    // DELETE /api/products/{id}
    public void Delete(int id)
    {
        var product = _db.FirstOrDefault(p => p.Id == id);
        if (product != null)
        {
            _db.Remove(product);
            Console.WriteLine($"HTTP 204 No Content: Deleted ID {id}");
        }
        else
        {
            Console.WriteLine($"HTTP 404 Not Found: ID {id} does not exist.");
        }
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("--- Starting Simulated Web API Session ---\n");
        var api = new ProductsApiController();

        // Simulate Client Requests
        api.GetAll();
        Console.WriteLine();
        
        api.Create("Keyboard", 75);
        Console.WriteLine();
        
        api.GetAll();
        Console.WriteLine();
        
        api.Delete(1);
        Console.WriteLine();
        
        api.Delete(99); // Triggers 404
        Console.WriteLine();
        
        api.GetAll();
    }
}

3. ASP.NET Core Middleware

Concept: Middleware are components that handle requests and responses in a pipeline. Each component can process the request before passing it to the next component (and process the response on the way back).

RequestTimingMiddleware.cs
using System.Diagnostics;

public class RequestTimingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestTimingMiddleware> _logger;

    public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var stopwatch = Stopwatch.StartNew();
        
        // Pass request to the next middleware in the pipeline
        await _next(context);
        
        stopwatch.Stop();
        var elapsedMs = stopwatch.ElapsedMilliseconds;
        
        // Log the time taken after the response comes back
        _logger.LogInformation($"Request {context.Request.Path} took {elapsedMs} ms.");
    }
}

// --- Registration in Program.cs ---
// var app = builder.Build();
// app.UseMiddleware<RequestTimingMiddleware>(); // Register here!
// app.UseAuthentication();
// app.UseAuthorization();
// app.MapControllers();
// app.Run();

4. Securing Web API (JWT)

Concept: JSON Web Tokens (JWT) are used to securely transmit information. The server issues a token upon login, and the client sends it in the HTTP Header for protected routes.

Program.cs (JWT Configuration)
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// 1. Configure JWT Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "MyApp",
            ValidAudience = "MyAppUsers",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisIsAVerySecretKey1234567890!"))
        };
    });

builder.Services.AddControllers();
var app = builder.Build();

// 2. Add Middleware to the pipeline
app.UseAuthentication(); // Must be BEFORE UseAuthorization
app.UseAuthorization();

app.MapControllers();
app.Run();

// --- How to protect a Controller ---
// [Authorize] // Add this attribute to your Controller class or specific Action
// [ApiController]
// [Route("api/[controller]")]
// public class SecureController : ControllerBase { ... }

5. ASP.NET Core Runtime & Embedded Server (Kestrel)

Concept: ASP.NET Core uses the Generic Host to manage app startup and lifetime. It includes Kestrel, a cross-platform, lightning-fast embedded HTTP server. Unlike old .NET, Kestrel is built directly into the application process.

Program.cs (Kestrel Configuration)
var builder = WebApplication.CreateBuilder(args);

// Configure Kestrel (Embedded HTTP Server) directly in code
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    // Set connection limits
    serverOptions.Limits.MaxConcurrentConnections = 100;
    serverOptions.Limits.MaxRequestBodySize = 10 * 1024; // 10 MB
    
    // You can also configure specific endpoints/ports here
    // serverOptions.ListenAnyIP(5000); 
    // serverOptions.ListenAnyIP(5001, listenOptions => listenOptions.UseHttps());
});

var app = builder.Build();

// The Host manages the lifetime. app.Run() starts the Kestrel server.
app.MapGet("/", () => "Hello from Kestrel Embedded Server!");
app.Run();
💡 Pro Tip for Hands-On: To practice creating a real ASP.NET Core Web API locally, open your terminal (Command Prompt / PowerShell) and run these commands:

dotnet new webapi -n MyFirstApi
cd MyFirstApi
dotnet run

This will launch the Kestrel server on your machine (usually at http://localhost:5000 or https://localhost:5001). You can then test your API using Postman or Swagger (built-in at /swagger).